home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 April: Mac OS SDK / Dev.CD Apr 96 SDK / Dev.CD Apr 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc / Sample Code / Sample Editors⁄Viewers / Cappuccino / Source / CappuccinoScripting.cpp < prev    next >
Encoding:
Text File  |  1995-12-11  |  15.4 KB  |  530 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        CappuccinoScripting.cpp
  3.     
  4.     Contents:    Implements scripting support.
  5.     
  6.     Written by:    Troy Gaul
  7.     
  8.     Copyright:    © 1995 by Apple Computer, Inc., all rights reserved.
  9. */
  10.  
  11. // -- Compiler/Preprocessor Switches --
  12.  
  13. #ifndef _COMPILERDEFS_
  14. #include "CompDefs.h"
  15. #endif
  16.  
  17. // -- OpenDoc Utilities --
  18.  
  19. #ifndef _EXCEPT_
  20. // Exceptions define several important macros (eg. CHECKENV)
  21. // which are used in the SOM method dispatch glue. If Except.h
  22. // is not included early enough, exceptions may not be thrown
  23. // correctly when returning from a SOM method with the "ev" parameter set.
  24. #include <Except.h>
  25. #endif
  26.  
  27. // -- Cappuccino Includes --
  28.  
  29. #ifndef _CAPPUCCINO_
  30. #include "Cappuccino.h"
  31. #endif
  32.  
  33. #ifndef _CAPPUCCINOACTION_
  34. #include "CappuccinoAction.h"
  35. #endif
  36.  
  37. #ifndef _CAPPUCCINOCONTENT_
  38. #include "CappuccinoContent.h"
  39. #endif
  40.  
  41. #ifndef SOM_CappuccinoSI_xh
  42. #include "som_CappuccinoSI.xh"
  43. #endif
  44.  
  45. // -- OpenDoc Includes --
  46.  
  47. #ifndef SOM_ODNameResolver_xh
  48. #include <NamRslvr.xh>
  49. #endif
  50.  
  51. #ifndef SOM_ODAppleEvent_xh
  52. #include <ODAplEvt.xh>
  53. #endif
  54.  
  55. #ifndef SOM_ODOSLToken_xh
  56. #include <ODOSLTkn.xh>
  57. #endif
  58.  
  59. #ifndef SOM_ODSession_xh
  60. #include <ODSessn.xh>
  61. #endif
  62.  
  63. // -- OpenDoc Utilities --
  64.  
  65. #ifndef _ODMEMORY_
  66. #include <ODMemory.h>
  67. #endif
  68.  
  69. #ifndef _ODDESUTL_
  70. #include <ODDesUtl.h>
  71. #endif
  72.  
  73. #ifndef _ODUTILS_
  74. #include <ODUtils.h>
  75. #endif
  76.  
  77. #ifndef _SEUTILS_
  78. #include <SEUtils.h>
  79. #endif
  80.  
  81. #ifndef _SIHELPER_
  82. #include <SIHelper.h>
  83. #endif
  84.  
  85. #ifndef _TEMPOBJ_
  86. #include <TempObj.h>
  87. #endif
  88.  
  89. // -- Macintosh Includes --
  90.  
  91. #ifndef __AEOBJECTS__
  92. #include <AEObjects.h>
  93. #endif
  94.  
  95. #ifndef __AEREGISTRY__
  96. #include <AERegistry.h>
  97. #endif
  98.  
  99. #ifndef _LIMITS
  100. #include <limits.h>
  101. #endif
  102.  
  103. //==============================================================================
  104. #pragma mark    • Utility functions/macros •
  105. //==============================================================================
  106.  
  107. //------------------------------------------------------------------------------
  108. // Macro
  109. //------------------------------------------------------------------------------
  110.  
  111. // Just a convenience definition.
  112. #define NULL_DESCRIPTOR_DEFINITION {typeNull, NULL}
  113.  
  114. //------------------------------------------------------------------------------
  115. // Function:    GetDirectParam
  116. // Origin:        Cappuccino
  117. //------------------------------------------------------------------------------
  118.  
  119. static void GetDirectParam( ODSession*        session, 
  120.                             AppleEvent*        message, 
  121.                             AEDesc*            evtDp )
  122. {
  123.     Environment*    ev            = somGetGlobalEnvironment();
  124.     AEDesc            localDP        = NULL_DESCRIPTOR_DEFINITION;
  125.     ODNameResolver* resolver    = session->GetNameResolver(ev);
  126.  
  127.     // Get the direct parameter
  128.     THROW_IF_ERROR(AEGetParamDesc(message, keyDirectObject, typeWildCard,
  129.                                   &localDP));
  130.  
  131.     // Make an ODDesc from it.
  132.     ODOSLToken*  tmpWrapper     = new ODOSLToken;
  133.     TempODObject tmpWrapperTemp = tmpWrapper;
  134.     THROW_IF_NULL(tmpWrapper);
  135.     tmpWrapper->InitODOSLToken(ev);
  136.     
  137.     THROW_IF_ERROR(AEDescToODDesc(&localDP, tmpWrapper));
  138.  
  139.     // Is it an OD token?
  140.     if ( resolver->IsODToken(ev, tmpWrapper) )
  141.     {
  142.         *evtDp = localDP;
  143.     }
  144.     else
  145.     {
  146.         AEDisposeDesc(&localDP);
  147.         THROW(errAEEventNotHandled);
  148.     }
  149. }
  150.  
  151. //==============================================================================
  152. #pragma mark    • Stub callbacks •
  153. //==============================================================================
  154.  
  155. //------------------------------------------------------------------------------
  156. // GetPropertyFromNULLStub
  157. //------------------------------------------------------------------------------
  158.  
  159. static pascal ODError GetPropertyFromNULLStub( ODPart*            part,
  160.                                                DescType            desiredClass,
  161.                                                ODOSLToken*        container,
  162.                                                DescType            containerClass,
  163.                                                DescType            form,
  164.                                                ODDesc*            selectionData,
  165.                                                ODOSLToken*        value,
  166.                                                ODSLong            refcon )
  167. {
  168.     ODError error = noErr;
  169.     
  170.     TRY
  171.         Environment* ev   = somGetGlobalEnvironment();
  172.         Cappuccino*  self = (Cappuccino*) refcon;
  173.  
  174.         self->GetPropertyFromNULL(ev, desiredClass, container, containerClass, 
  175.                                   form, selectionData, value);
  176.     CATCH_ALL
  177.         error = ErrorCode();
  178.     ENDTRY
  179.     
  180.     return error;
  181. }
  182.  
  183. //------------------------------------------------------------------------------
  184. // HandleSetDataGetStub
  185. //------------------------------------------------------------------------------
  186.  
  187. static pascal ODError HandleSetDataStub( ODPart*            part,
  188.                                          ODAppleEvent*        message,
  189.                                          ODAppleEvent*        reply,
  190.                                          ODSLong            refcon )
  191. {
  192.     ODError error = noErr;
  193.     
  194.     TRY
  195.         Environment* ev   = somGetGlobalEnvironment();
  196.         Cappuccino*  self = (Cappuccino*) refcon;
  197.  
  198.         self->HandleSetData(ev, message, reply);
  199.     CATCH_ALL
  200.         error = ErrorCode();
  201.     ENDTRY
  202.     
  203.     return error;
  204. }
  205.  
  206. //------------------------------------------------------------------------------
  207. // HandleGetDataStub
  208. //------------------------------------------------------------------------------
  209.  
  210. static pascal ODError HandleGetDataStub( ODPart*            part,
  211.                                          ODAppleEvent*        message,
  212.                                          ODAppleEvent*        reply,
  213.                                          ODSLong            refcon )
  214. {
  215.     ODError error = noErr;
  216.     
  217.     TRY
  218.         Environment* ev   = somGetGlobalEnvironment();
  219.         Cappuccino*  self = (Cappuccino*) refcon;
  220.  
  221.         self->HandleGetData(ev, message, reply);
  222.     CATCH_ALL
  223.         error = ErrorCode();
  224.     ENDTRY
  225.     
  226.     return error;
  227. }
  228.  
  229. //==============================================================================
  230. #pragma mark    • Cappuccino Scripting •
  231. //==============================================================================
  232.  
  233. //------------------------------------------------------------------------------
  234. // Method:        ConstructSemanticInterface
  235. // Origin:        Cappuccino
  236. //------------------------------------------------------------------------------
  237.  
  238. void Cappuccino::ConstructSemanticInterface( Environment* ev )
  239. {
  240.     // The following lines must be used in strict order in order to initalize
  241.     // The CappuccinoSI and SIHelper classes correctly.
  242.     fSemanticInterface = new som_CappuccinoSI;
  243.     THROW_IF_NULL(fSemanticInterface);
  244.     
  245.     SIHelper* semItfcHelper = new SIHelper;
  246.     semItfcHelper->InitSIHelper(fSession, fSemanticInterface);
  247.     
  248.     // The Extension interface requires that a pointer to the real part, not the
  249.     // part wrapper, be passed to InitExtension. Therefore, we get that
  250.     // reference here.
  251.     ODPart*    realPart = fSelf->GetRealPart(ev);
  252.     fSemanticInterface->InitCPlusSemanticInterface(ev, realPart, semItfcHelper, fSession);
  253.     fSelf->ReleaseRealPart(ev);
  254.     
  255.     SIHelper* helper = (SIHelper*) fSemanticInterface->GetSIHelper(ev);
  256.     
  257.     // We install one object accessor in order to get a token for the contents
  258.     // property and two event handlers to handle get data and set data.
  259.     
  260.     ODObjectAccessorUPP theAccessorUPP;
  261.  
  262.     theAccessorUPP = NewODObjectAccessorProc(GetPropertyFromNULLStub);
  263.     helper->InstallObjectAccessor(cProperty, typeNull, theAccessorUPP,
  264.                                   (ODSLong) this);
  265.     
  266.     ODEventHandlerUPP theEventHandlerUPP;
  267.     
  268.     theEventHandlerUPP = NewODEventHandlerProc(HandleSetDataStub);
  269.     helper->InstallEventHandler(kAECoreSuite, kAESetData, theEventHandlerUPP,
  270.                                 (ODSLong) this);
  271.     
  272.     theEventHandlerUPP = NewODEventHandlerProc(HandleGetDataStub);
  273.     helper->InstallEventHandler(kAECoreSuite, kAEGetData, theEventHandlerUPP,
  274.                                 (ODSLong) this);
  275. }
  276.  
  277. //------------------------------------------------------------------------------
  278. // Method:        GetPropertyFromNULL
  279. // Origin:        Cappuccino
  280. //------------------------------------------------------------------------------
  281.  
  282. void Cappuccino::GetPropertyFromNULL( Environment*        ev,
  283.                                       DescType            desiredClass,
  284.                                       ODOSLToken*        container,
  285.                                       DescType            containerClass,
  286.                                       DescType            form,
  287.                                       ODDesc*            selectionData,
  288.                                       ODOSLToken*        value )
  289. {
  290.     ODNameResolver*    resolver = fSession->GetNameResolver(ev);
  291.     
  292.     // We throw errAEEventNotHandled so that OpenDoc's default Semantic
  293.     // Interface will try to handle this access even if we couldnt't
  294.     if (form != formPropertyID)
  295.         THROW(errAEEventNotHandled);
  296.  
  297.     AEDesc        realData        = NULL_DESCRIPTOR_DEFINITION;
  298.     TempAEDesc    realDataTemp    = &realData;
  299.     THROW_IF_ERROR(ODDescToAEDesc(selectionData, &realData));
  300.     
  301.     DescType propID = FIRSTBYTESFROMHANDLE(realData.dataHandle, DescType);
  302.  
  303.     switch ( propID )
  304.     {
  305.         case pContents:
  306.         {
  307.             // Create a descriptor that represents the object that we are
  308.             // being asked for. For this object, which is the contents
  309.             // property, we choose to set the descriptorType to cProperty
  310.             // and to put the id of the property into the first four bytes
  311.             // of the handle of the descriptor. We could have chosen a
  312.             // different representation if we wanted to. It is also
  313.             // common to instantiate a C++ object and place a reference to
  314.             // it in the dataHandle of the token.
  315.             AEDesc        tokenDesc        = NULL_DESCRIPTOR_DEFINITION;
  316.             TempAEDesc    tokenDescTemp    = &tokenDesc;
  317.             THROW_IF_ERROR(AECreateDesc(cProperty, &propID, sizeof(propID),
  318.                                         &tokenDesc));
  319.             
  320.             // If your part's contents vary from display frame to display
  321.             // frame then use the below code to determine which frame this
  322.             // object access applies to.
  323.     //        ODPart* contextPart;
  324.     //        ODFrame* contextFrame;
  325.     //        resolver->GetContextFromToken(ev, container, &contextPart,
  326.     //                                      &contextFrame);
  327.  
  328.             // This utility routine gets the user token from the token and
  329.             // updates it with the data passed in. See SEUtils.cpp.
  330.             UpdateUserToken(ev, resolver, value, &tokenDesc);
  331.         }
  332.         break;
  333.             
  334.         default:
  335.             THROW(errAEEventNotHandled);        // let the default try
  336.             break;
  337.     }
  338. }
  339.  
  340. //------------------------------------------------------------------------------
  341. // Method:        HandleSetData
  342. // Origin:        Cappuccino
  343. //------------------------------------------------------------------------------
  344.  
  345. void Cappuccino::HandleSetData( Environment*        ev,
  346.                                 ODAppleEvent*        message,
  347.                                 ODAppleEvent*        reply )
  348. {
  349.     ODNameResolver* resolver = fSession->GetNameResolver(ev);
  350.     
  351.     // Get an AEDesc version of our Apple event.
  352.     AppleEvent    realMessage        = NULL_DESCRIPTOR_DEFINITION;
  353.     TempAEDesc    realMessageTemp    = &realMessage;
  354.     THROW_IF_ERROR(ODDescToAEDesc(message, &realMessage));
  355.     
  356.     // Get the data that will using for "setting".
  357.     AEDesc        theData        = NULL_DESCRIPTOR_DEFINITION;
  358.     TempAEDesc    theDataTemp    = &theData;
  359.     THROW_IF_ERROR(AEGetKeyDesc(&realMessage, keyAEData, typeWildCard, &theData));
  360.     
  361.     AEDesc        token        = NULL_DESCRIPTOR_DEFINITION;
  362.     TempAEDesc    tokenTemp    = &token;
  363.     {
  364.         // We need to create an ODDesc version of this so that we can call the
  365.         // OpenDoc routines IsODToken and GetUserToken with it.
  366.         ODOSLToken*     tokenODDesc     = new ODOSLToken;
  367.         TempODObject tokenODDescTemp = tokenODDesc;
  368.         THROW_IF_NULL(tokenODDesc);
  369.         tokenODDesc->InitODOSLToken(ev);
  370.         {
  371.             // Get the direct parameter of the event. This will be our token.
  372.             AEDesc        evtDp        = NULL_DESCRIPTOR_DEFINITION;
  373.             TempAEDesc    evtDpTemp    = &evtDp;
  374.             GetDirectParam(fSession, &realMessage, &evtDp);
  375.             
  376.             THROW_IF_ERROR(AEDescToODDesc(&evtDp, tokenODDesc));
  377.         }
  378.             
  379.         // We might not actually get a token in the direct parameter. We
  380.         // need to make sure it's an ODToken.
  381.         if ( !resolver->IsODToken(ev, tokenODDesc) )
  382.             THROW(errAENoSuchObject);
  383.         
  384.         // Get the "user" token. This is the one that we have actually
  385.         // modified in our object accessor routine earlier.
  386.         ODDesc* myTokenODDesc;
  387.         myTokenODDesc = resolver->GetUserToken(ev, tokenODDesc);
  388.         
  389.         // Get an AEDesc version of same. Note that we could have extracted the
  390.         // data using ODDesc::GetRawData as well.
  391.         THROW_IF_ERROR(ODDescToAEDesc(myTokenODDesc, &token));
  392.     }
  393.         
  394.     switch ( token.descriptorType )
  395.     {
  396.         case typeProperty:
  397.         {
  398.             // We know that if the descriptorType is typeProperty, we
  399.             // earlier placed a property ID DescType in the first four
  400.             // bytes of the dataHandle.
  401.             DescType propID = FIRSTBYTESFROMHANDLE(token.dataHandle, DescType);
  402.             
  403.             if ( propID != pContents )
  404.                 THROW(errAEEventNotHandled);
  405.             
  406.             ThrowIfCantCoerce(&theData, typeChar);
  407.         
  408.             // Get the data out of the dataHandle and change our
  409.             // private data.
  410.             Size textLength = GetHandleSize(theData.dataHandle);
  411.             THROW_IF_ERROR(MemError());
  412.             if (textLength > UCHAR_MAX)
  413.                 THROW(errAEEventNotHandled);
  414.             
  415.             // Put the text into a string.
  416.             Str255 string;
  417.             string[0] = textLength;
  418.             ODBlockMove(*theData.dataHandle, &string[1], textLength);
  419.             
  420.             // Create a new content object for the string.
  421.             CCappuccinoContent* content = new CCappuccinoContent(this);
  422.             TempRefCounted contentTemp = content;
  423.             content->InitCappuccinoContent(ev, string);
  424.             
  425.             // Create an action and do it.
  426.             CSetTextAction* action = new CSetTextAction(this, content);
  427.             action->Perform(ev);
  428.         }
  429.         break;
  430.         
  431.         default:
  432.             THROW(errAEEventNotHandled);
  433.     }
  434. }
  435.  
  436. //------------------------------------------------------------------------------
  437. // Method:        HandleGetData
  438. // Origin:        Cappuccino
  439. //------------------------------------------------------------------------------
  440.  
  441. void Cappuccino::HandleGetData( Environment*        ev,
  442.                                 ODAppleEvent*        message,
  443.                                 ODAppleEvent*        reply )
  444. {
  445.     ODNameResolver* resolver = fSession->GetNameResolver(ev);
  446.     
  447.     // Get AEDesc versions of the event and the reply
  448.     AppleEvent    realMessage        = NULL_DESCRIPTOR_DEFINITION;
  449.     TempAEDesc    realMessageTemp    = &realMessage;
  450.     THROW_IF_ERROR(ODDescToAEDesc(message, &realMessage));
  451.  
  452.     AppleEvent    realReply        = NULL_DESCRIPTOR_DEFINITION;
  453.     TempAEDesc    realReplyTemp    = &realReply;
  454.     THROW_IF_ERROR(ODDescToAEDesc(reply, &realReply));
  455.     
  456.     AEDesc        token            = NULL_DESCRIPTOR_DEFINITION;
  457.     TempAEDesc    tokenTemp        = &token;    
  458.     {
  459.         ODOSLToken*     tokenODDesc     = new ODOSLToken;
  460.         TempODObject tokenODDescTemp = tokenODDesc;
  461.         THROW_IF_NULL(tokenODDesc);
  462.         tokenODDesc->InitODOSLToken(ev);
  463.  
  464.         // Get the direct parameter which will contain our token. We must also
  465.         // create an ODDesc version so that we can call the OpenDoc methods
  466.         // IsODToken and GetUserToken.
  467.         {
  468.             AEDesc        evtDp        = NULL_DESCRIPTOR_DEFINITION;
  469.             TempAEDesc    evtDpTemp    = &evtDp;
  470.             GetDirectParam(fSession, &realMessage, &evtDp);
  471.             
  472.             THROW_IF_ERROR(AEDescToODDesc(&evtDp, tokenODDesc));
  473.         }
  474.         
  475.         // We might not actually get a token in the direct parameter. We
  476.         // need to make sure it's an ODToken.
  477.         if ( !resolver->IsODToken(ev, tokenODDesc) )
  478.             THROW(errAENoSuchObject);
  479.         
  480.         // Get the "user" token which contains the token that we set up earlier.
  481.         ODDesc* myTokenODDesc = resolver->GetUserToken(ev, tokenODDesc);
  482.         THROW_IF_ERROR(ODDescToAEDesc(myTokenODDesc, &token));
  483.     }
  484.     
  485.     // Next, get the requested return type, if it exists.
  486.     DescType reqType;
  487.     {
  488.         Size theSize;
  489.         OSErr error = AEGetParamPtr(&realMessage, keyAERequestedType, typeType,
  490.                                     &reqType, (Ptr) &reqType, sizeof(reqType), &theSize);
  491.         
  492.         // Not an error if return type is not found -- use wildcard type.
  493.         if (error == errAEDescNotFound)
  494.             reqType = typeWildCard;
  495.         else
  496.             THROW_IF_ERROR(error);
  497.     }
  498.     
  499.     AEDesc        objectData        = NULL_DESCRIPTOR_DEFINITION;
  500.     TempAEDesc    objectDataTemp    = &objectData;
  501.             
  502.     switch ( token.descriptorType )
  503.     {
  504.         case typeProperty:
  505.             // Create a descriptor containing our data. We try to coerce
  506.             // it if we were asked for a type that's different from the
  507.             // one we would ordinarily create.
  508.             CCappuccinoContent* content = this->GetContent();
  509.             
  510.             THROW_IF_ERROR(AECreateDesc(typeChar, &content->GetString()[1],
  511.                                         content->GetString()[0], &objectData));
  512.             
  513.             if ( reqType != typeChar && reqType != typeWildCard )
  514.                 ThrowIfCantCoerce(&objectData, reqType);
  515.             break;
  516.             
  517.         default:
  518.             THROW(errAEEventNotHandled);
  519.     }
  520.     
  521.     // Place the result data into the reply
  522.     THROW_IF_ERROR(AEPutParamDesc(&realReply, keyAEResult, &objectData));
  523.  
  524.     // Update the ODDesc version of the reply. The AEDesc version is just
  525.     // a local copy that we use so that we can use all the AE manager
  526.     // routines on it.
  527.     THROW_IF_ERROR(AEDescToODDesc(&realReply, reply));
  528. }
  529.  
  530.